﻿using System;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Activation;
using CoreEx.Services;
using LinFu.IoC.Interfaces;
using LinFu.IoC;

namespace CoreEx.ServiceModel
{
    /// <summary>
    /// A custom <see cref="ServiceHostFactory"/> that initializes the 
    /// <see cref="IServiceContainer"/> and creates a <see cref="ServiceHost"/> instance.
    /// </summary>
    /// <seealso cref="ServiceHost"/>
    public class ServiceContainerServiceHostFactory : ServiceHostFactory
    {
        private static readonly IServiceContainer _serviceContainer;

        /// <summary>
        /// Initializes the <see cref="IServiceContainer"/> instance.
        /// </summary>
        static ServiceContainerServiceHostFactory()
        {
            _serviceContainer = ServiceLocator.Container;
        }


        /// <summary>
        /// Creates a <see cref="T:System.ServiceModel.ServiceHost"/> with specific base addresses and initializes it with specified data.
        /// </summary>
        /// <param name="constructorString">The initialization data passed to the <see cref="T:System.ServiceModel.ServiceHostBase"/> instance being constructed by the factory.</param>
        /// <param name="baseAddresses">The <see cref="T:System.Array"/> of type <see cref="T:System.Uri"/> that contains the base addresses for the service hosted.</param>
        /// <returns>
        /// A <see cref="T:System.ServiceModel.ServiceHost"/> with specific base addresses.
        /// </returns>
        /// <exception cref="T:System.ArgumentNullException">
        /// 	<paramref name="baseAddresses"/> is null.</exception>
        /// <exception cref="T:System.InvalidOperationException">There is no hosting context provided or <paramref name="constructorString"/> is null or empty.</exception>
        public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
        {
         
            
            var serviceType =
                _serviceContainer.AvailableServices.Where(s => s.ServiceType.FullName.Equals(constructorString,StringComparison.InvariantCultureIgnoreCase)).Select(
                    s => s.ServiceType).FirstOrDefault();
            return CreateServiceHost(serviceType, baseAddresses);
        }

        /// <summary>
        /// Creates a <see cref="T:System.ServiceModel.ServiceHost"/> for a specified type of service with a specific base address.
        /// </summary>
        /// <param name="serviceType">Specifies the type of service to host.</param>
        /// <param name="baseAddresses">The <see cref="T:System.Array"/> of type <see cref="T:System.Uri"/> that contains the base addresses for the service hosted.</param>
        /// <returns>
        /// A <see cref="T:System.ServiceModel.ServiceHost"/> for the type of service specified with a specific base address.
        /// </returns>
        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            var serviceHost = _serviceContainer.GetService<ServiceHost>(new object[] { serviceType, baseAddresses });
            return serviceHost;
        }


    }
}